

#include <cexml/cexml.h>
#include <libxml/tree.h>

#include <assert.h>

static bool __xml_initialized = false;

ceXmlElement::ceXmlElement (xmlNode* node)
	: node (node)
{
}

ceXmlElement::~ceXmlElement ()
{
}

void ceXmlElement::AssignNode (xmlNode* node)
{
	this->node = node;
}

bool ceXmlElement::IsValid () const
{
	return node != 0;
}

ceString ceXmlElement::GetTagName () const
{
	assert (node);

	return (const char*)node->name;
}

ceString ceXmlElement::GetAttribute (const char* name, const char* defaultValue) const
{
	assert (node != 0);
  
  for (xmlAttr* attr = node->properties; attr; attr = attr->next)
    {
      if (strcmp ((const char*)attr->name, name) == 0)
        {
          return (const char*)attr->children->content;
        }
    }
  return defaultValue;
}

bool ceXmlElement::HasAttribute (const char* name) const
{
	assert(node != 0);
  for (xmlAttr* attr = node->properties; attr; attr = attr->next)
    {
      if (strcmp ((const char*)attr->name, name) == 0)
        {
          return true;
        }
    }
  return false;
}

unsigned ceXmlElement::GetNumberOfChildren (const char* tagName) const
{
	assert(node);
  unsigned num=0;

  bool testTagName = tagName != 0 && strlen(tagName) != 0;

  for (xmlNode* child = node->children; child; child = child->next)
    {
      if (child->type == XML_ELEMENT_NODE && 
          (!testTagName  ||
          strcmp ((const char*)child->name, tagName) == 0))
        {
          num++;
        }
    }

  return num;
}

ceXmlElement ceXmlElement::GetChild (const char* tagName) const
{
	return GetChild (0, tagName);
}

ceXmlElement ceXmlElement::GetChild (unsigned idx, const char* tagName) const
{
	assert (node != 0);
  unsigned num=0;
  bool testTagName = tagName != 0 && strlen(tagName) != 0;

  for (xmlNode* child = node->children; child; child = child->next)
    {
      if (child->type == XML_ELEMENT_NODE && 
          (!testTagName  ||
          strcmp((const char*)child->name, tagName) == 0))
        {
          if (num == idx)
            {
              return ceXmlElement (child);
            }
          num++;
        }
    }
	// return an invalid element when the specified node is 
	// not present
  return ceXmlElement (NULL);
}

int ceXmlElement::GetIntAttribute (const char* attributeName) const
{
	ceString val = GetAttribute (attributeName);
	return atoi (val.c_str ());
}

float ceXmlElement::GetFloatAttribute (const char* attributeName) const
{
	ceString val = GetAttribute (attributeName);
	return atof (val.c_str ());
}


ceString ceXmlElement::GetString () const
{
	assert (node != 0);
  unsigned num=0;

  for (xmlNode* child = node->children; child; child = child->next)
    {
			if (child->type == XML_TEXT_NODE)
        {
					return (const char*)child->content;
        }
    }
	// return an invalid element when the specified node is 
	// not present
  return "";
}


ceXmlDocument::ceXmlDocument ()
	: doc (0)
{
}

void __xml_initialize ()
{
	if (!__xml_initialized)
	{
		LIBXML_TEST_VERSION;
		__xml_initialized = true;
	}
}

static int __xml_io_read (void* context, char* data, int length)
{
	iFile* file = static_cast<iFile*>(context);
	assert (file != 0);
	return file->Read (data, length);
}

static int __xml_io_close (void* context)
{
	iFile* file = static_cast<iFile*>(context);
	assert (file != 0);
	
	file->Close ();
	return  0;
}

bool ceXmlDocument::Open (iFile* file)
{
	__xml_initialize ();

	doc = xmlReadIO (__xml_io_read, __xml_io_close, file, 0, 0, 0);

	return doc != 0;
}


bool ceXmlDocument::Open (const ceString& filename)
{
	__xml_initialize ();
	doc = xmlReadFile(filename.c_str(), 0, 0);
	return doc != 0;
}

ceXmlElement ceXmlDocument::GetRootElement () const
{
	assert (doc != 0);

	return ceXmlElement (xmlDocGetRootElement (doc));
}